package com.sh.common;

import javax.naming.Context;
import javax.naming.InitialContext;

//import org.apache.commons.beanutils.BeanUtils;
import org.hibernate.HibernateException;
import org.hibernate.Session;
//import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.internal.SessionFactoryRegistry;
import org.hibernate.service.ServiceRegistry;
//import org.hibernate.service.ServiceRegistryBuilder;


/**
 * Configures and provides access to Hibernate sessions, tied to the current
 * thread of execution. Follows the Thread Local Session pattern, see
 * {@link http://hibernate.org/42.html }.
 */
public class HibernateSessionFactory {

	/**
	 * Location of hibernate.cfg.xml file. Location should be on the classpath
	 * as Hibernate uses #resourceAsStream style lookup for its configuration
	 * file. The default classpath location of the hibernate config file is in
	 * the default package. Use #setConfigFile() to update the location of the
	 * configuration file for the current session.
	 */
	private static String CONFIG_FILE_LOCATION = "../config/hibernate.cfg.xml";
	private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
	private static Configuration configuration = null; // 首次判断使用，所以置成null
	private static org.hibernate.SessionFactory sessionFactory;
	private static String configFile = CONFIG_FILE_LOCATION;
	private static ServiceRegistry serviceRegistry;
	private static SessionFactoryRegistry sessionFactoryRegistry = SessionFactoryRegistry.INSTANCE;
	private HibernateSessionFactory() {
	}
	
	public static ThreadLocal<Session> getHSessionThreadLocal(){
		return threadLocal;
	}

	/**
	 * Returns the ThreadLocal Session instance. Lazy initialize the
	 * <code>SessionFactory</code> if needed.
	 * 
	 * @return Session
	 * @throws HibernateException
	 */
	public static Session getSession() throws HibernateException {
		Session session = (Session) threadLocal.get();

		if (session == null || !session.isOpen() || !session.isConnected()) {			
			if (sessionFactory == null) {
				rebuildSessionFactory();
			}
			session = (sessionFactory != null) ? sessionFactory.openSession()
					: null;
			threadLocal.set(session);
		}

		return session;
	}

	/**
	 * Rebuild hibernate session factory
	 * 
	 */
	public static void rebuildSessionFactory() {
		try {
			if(null != configuration){
				// Add by zonghuah at 2016-08-21
				// 先清空内存中的 SessionFactoryRegistry中sessionFactoryMap的sessionFactoryImpl内容，否则内存泄漏
				// 这样的话，sessionFactoryImpl实例在垃圾回收时能收回；configuration实例在垃圾回收也能收回
				// getNamedSessionFactory使用空名，应该与hibernate.cfg.xml中的<session-factory name="">配置有关
				try{					
					sessionFactory = sessionFactoryRegistry.getNamedSessionFactory("");
					//sessionFactory.close(); zjf 20180601 系统经常卡住，注掉
					sessionFactory = null;
				}catch(Exception e){
					com.sh.common.LogUtil.getAppDebugLog().error("收回sessionFactory垃圾出错", e);
				}
			}
			configuration = new Configuration().configure(configFile);		
			//configuration = new Configuration().configure();
			String jndi = configuration.getProperty("hibernate.connection.datasource");
			//System.out.println("jndi=" + jndi);
			Context ctx = new InitialContext();
			javax.sql.DataSource sqlSource = (javax.sql.DataSource) ctx.lookup(jndi);
			
//			String url = BeanUtils.getProperty(sqlSource, "url");
//			String username = BeanUtils.getProperty(sqlSource, "username");
//			String password = BeanUtils.getProperty(sqlSource, "password");			
//			
//			if(username.startsWith("___")){
//				url = SystemSetUtil.unPasswordString(url);
//				username = SystemSetUtil.unPasswordString(username);
//				password = SystemSetUtil.unPasswordString(password);
//				
//				BeanUtils.setProperty(sqlSource, "url", url);
//				BeanUtils.setProperty(sqlSource, "username", username);
//				BeanUtils.setProperty(sqlSource, "password", password);
//			}
			//sessionFactory = configuration.buildSessionFactory();			
			serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).getBootstrapServiceRegistry();
			sessionFactory = configuration.buildSessionFactory(serviceRegistry);  
			//ServiceRegistryBuilder serviceRegistry = new ServiceRegistryBuilder();
			//sessionFactory = configuration.buildSessionFactory(serviceRegistry.buildServiceRegistry());
		} catch (Exception e) {
			sessionFactory = null;
			serviceRegistry = null;
			configuration = null;
			com.sh.common.LogUtil.getAppDebugLog().error("%%%% Error Creating SessionFactory %%%%", e);			
			e.printStackTrace();
		}
	}

	/**
	 * Close the single hibernate session instance.
	 * 
	 * @throws HibernateException
	 */
	public static void closeSession() throws HibernateException {
		Session session = (Session) threadLocal.get();
		threadLocal.set(null);

		if (session != null) {
			session.close();
		}
	}

	/**
	 * return session factory
	 * 
	 */
	public static org.hibernate.SessionFactory getSessionFactory() {
		return sessionFactory;
	}

	/**
	 * return session factory
	 * 
	 * session factory will be rebuilded in the next call
	 */
	public static void setConfigFile(String configFile) {
		HibernateSessionFactory.configFile = configFile;
		sessionFactory = null;
	}

	/**
	 * return hibernate configuration
	 * 
	 */
	public static Configuration getConfiguration() {
		return configuration;
	}

}